package com.web.cloud.controller.pub;

import com.github.pagehelper.PageInfo;
import com.web.cloud.constances.DBConsts;
import com.web.cloud.exception.BusinessException;
import com.web.cloud.model.pub.IOrgBaseModel;
import com.web.cloud.service.pub.OrgBaseService;
import com.web.cloud.utils.ReflectUtils;
import com.web.cloud.wapper.AbstractDataTableQueryArgWapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 列表界面Controller类
 * Created by hubo on 16/3/25
 */
@SuppressWarnings("unchecked")
public abstract class ListViewController<T extends IOrgBaseModel, V extends AbstractDataTableQueryArgWapper> extends BasicController {

    private static final Logger log = LoggerFactory.getLogger(ListViewController.class);

    /**
     * 返回基础服务对象
     * @return 基础服务对象
     */
    protected abstract OrgBaseService<T> getService();
    /**
     *  查询对象转换成Json对象
     */
    protected abstract Object transformQueryDateToJson(int index, T t);


    public Map<String, Object> get(String id) {
        Map<String, Object> result = new HashMap<>();
        result.put("result", "success");
        result.put("data", transformQueryDateToJson(1, getService().get(id)));
        return result;
    }

    /**
     * 数据保存
     * @param t 数据信息
     * @param errors 错误信息
     * @return 返回数据正确信息
     */
    public Map<String, Object> save(T t, Errors errors) {

        Map<String, Object> result = new HashMap<>();

        if(errors.getErrorCount() > 0) {
            return handleErrors(errors);
        }

        try {
            getService().save(t);
            result.put("result", "success");
        } catch (BusinessException e) {
            log.error(e.getMessage(), e);
            result.put("result", "error");
        }

        return result;
    }

    /**
     * 更新数据
     * @param t 数据对象
     * @param errors 错误信息
     * @return 返回数据正确信息
     */
    public Map<String, Object> update(T t, Errors errors) {

        Map<String, Object> result = new HashMap<>();

        if(errors.getErrorCount() > 0) {
            return handleErrors(errors);
        }

        try {
            getService().update(t);
            result.put("result", "success");
        } catch (BusinessException e) {
            log.error(e.getMessage(), e);
            result.put("result", "error");
            result.put("errorMsg", e.getMessage());
        }

        return result;
    }


    /**
     * 列表分页查询数据
     * @param arg 数据表查询参数
     * @return 查询数据VO
     */
    protected Map<String, Object> listData(V arg) {
        return listData(arg, null);
    }

    /**
     * 列表分页查询数据
     * @param arg 数据表查询参数
     * @return 查询数据VO
     */
    protected Map<String, Object> listData(V arg, T where) {

        Map<String, Object> result = new HashMap<>();

        PageInfo<T> pageInfo;
        try {
            pageInfo = getService().selectLikePage(arg.getSearchText(), arg.getPageNum(), arg.getLength(), arg.getOrderStr(), where);
        } catch (Exception e) {
            log.error(e.getMessage(),e);
            pageInfo = new PageInfo<>();
        }

        List<Object> data = new ArrayList<>();

        int index = 1;

        for (T t : pageInfo.getList()) {
            data.add(transformQueryDateToJson(index, t));
            index++;
        }

        result.put("draw", arg.getDraw());
        result.put("recordsTotal", pageInfo.getTotal());
        result.put("recordsFiltered", pageInfo.getTotal());
        result.put("data", data);

        return result;

    }

    /**
     * 批量删除数据
     * @param ids 数据id
     * @param ts 数据ts
     * @return 返回数据正确信息
     * @throws Exception
     */
    public Map<String, Object> batchDelete(String[] ids, Long[] ts) throws Exception {

        Map<String, Object> result = new HashMap<>();

        List<T> voList = assembleVOs(ids, ts);

        try {
            getService().delete(voList);
            result.put("result", "success");
        } catch (BusinessException e) {
            log.error(e.getMessage(), e);
            result.put("result", "error");
            result.put("errorMsg", e.getMessage());
        }

        return result;
    }

    /**
     * 更新数据状态(启用或停用)
     * @param status 数据状态
     * @param ids id
     * @param ts ts
     * @return 返回数据正确信息
     * @throws Exception
     */
    public Map<String, Object> updateStatus(Short status, String[] ids, Long[] ts) throws Exception {

        Map<String, Object> result = new HashMap<>();

        List<T> voList = assembleVOs(ids, ts);

        try {
            if(status.equals(DBConsts.STATUS_ENABLE)) {
                getService().enable(voList);
            }else {
                getService().disable(voList);
            }
            result.put("result", "success");
        } catch (BusinessException e) {
            log.error(e.getMessage(), e);
            result.put("result", "error");
            result.put("errorMsg", e.getMessage());
        }

        return result;
    }

    /**
     * 处理错误信息
     * @param errors 错误信息
     * @return 错误信息json
     */
    protected Map<String, Object> handleErrors(Errors errors) {
        Map<String, Object> result = new HashMap<>();
        result.put("result", "error");
        for (FieldError err : errors.getFieldErrors()) {
            result.put("err_" + err.getField(), err.getDefaultMessage());
        }
        return result;
    }

    /**
     * 组装VO信息(根据id和ts,主要用于批量操作)
     * @param ids ids
     * @param ts ts
     * @return 组装好后的VOList
     * @throws Exception
     */
    protected List<T> assembleVOs(String[] ids, Long[] ts) throws Exception {

        List<T> voList = new ArrayList<>();

        Class<T> tClass = ReflectUtils.findParameterizedType(this.getClass());

        for (int i = 0; i < ids.length; i++) {
            T role = tClass.newInstance();
            role.setId(ids[i]);
            if(ts != null && ts[i] != null) {
                role.setTs(ts[i]);
            }
            voList.add(role);
        }
        return voList;
    }
}
